import 'dart:math';
import 'dart:ui';

/// 球类，表示每个球的基本信息
class Ball {
  final String name;

  Ball({required this.name});
}

/// 配置类，用于管理每个球的状态和行为
class BadgeBallConfig {
  // 加速度  9.8 右下 是正数
  final Acceleration _acceleration = Acceleration(0, 0);
  // 时间常量，用于计算位移和速度， 一帧时间？
  final double time = 0.02;
  // 碰撞回调函数F
  late Function(Offset) collusionCallback;
  // 大小
  Size size = const Size(100, 100);
  // 速度
  Speed _speed = Speed(0, 0);
  // 当前位置
  late Offset _position;

  double _angle = 0;
  double _angleSpeed = 0;

  // 每个球的基本信息
  late Ball ball;

  // 衰减系数，用于模拟碰撞后的速度衰减
  double ballNormalAccelerationCoefficient = 0.95;
  double ballOtherAccelerationCoefficient = 0.8;
  // 衰减系数，用于墙壁碰撞后的速度衰减
  double wallAttenuationCoefficient = 0.7;
  //加速度 系数
  double accelerationCoefficient = 0.7;

  double limitX = 0;
  double limitY = 0;

  void setLimit(double limit_X, double limit_Y ) {
    limitX = limit_X;
    limitY = limit_Y;
  }

  /// 设置球的位置
  void setPosition(Offset offset) {
    _position = offset;
  }

  /// 设置初速度
  void setInitSpeed(Speed speed) {
    _speed = speed;
  }

  /// 设置加速度
  void setAcceleration(double x, double y) {
    _acceleration.x = x * accelerationCoefficient;
    _acceleration.y = y * accelerationCoefficient;
  }

  /// 获取当前速度
  Speed getCurrentSpeed() => _speed;

  double getAngleSpeed(){
    return _angleSpeed;
  }

  void setAngleSpeed(double angleSpeed){
    _angleSpeed = angleSpeed;
  }

  /// 获取当前中心位置
  Offset getCurrentCenter() => Offset(
    _position.dx + size.width / 2,
    _position.dy + size.height / 2,
  );

  /// 获取当前位置
  Offset getCurrentPosition() => _position;

  /// 惯性开始，根据加速度启动速度
  void inertiaStart(double x, double y) {
    if (x.abs() > _acceleration.x.abs()) _speed.x += x;
    if (y.abs() > _acceleration.y.abs()) _speed.y += y;
  }

  /// 碰撞后的处理，更新速度和位置，并调用碰撞回调
  void afterCollusion(Offset offset, Speed speed, bool isLeft, bool isTop) {
    double accelerationCoefficientX = 1;
    double accelerationCoefficientY = 1;
    if(_acceleration.x.abs() > _acceleration.y.abs()){
      if(_acceleration.x < 0 && !isLeft){
        accelerationCoefficientX = ballOtherAccelerationCoefficient;
      } else if(_acceleration.x > 0 && isLeft){
        accelerationCoefficientX = ballOtherAccelerationCoefficient;
      }
    } else {
      if(_acceleration.y < 0 && !isTop){
        accelerationCoefficientY = ballOtherAccelerationCoefficient;
      } else if(_acceleration.y > 0 && isTop){
        accelerationCoefficientY = ballOtherAccelerationCoefficient;
      }
    }

    setOppositeSpeedForCollusion(speed, accelerationCoefficientX, accelerationCoefficientY);

    _position = offset;
    collusionCallback(offset);
  }

  void setOppositeSpeedForCollusion(Speed speed, double accelerationCoefficientX, double accelerationCoefficientY) {

    _speed.x = speed.x * ballNormalAccelerationCoefficient;
    double dx = (1 - accelerationCoefficientX) * _speed.x.abs();
    if(accelerationCoefficientX != 1 && dx < _acceleration.x.abs() * time){
      dx = _acceleration.x.abs() * time * 10.2;
    }
    double resultX = (_speed.x.abs() - dx);
    if(resultX < 0){
      _speed.x = 0;
    } else {
      if(_speed.x > 0){
        _speed.x = resultX;
      } else {
        _speed.x = -resultX;
      }
    }

    _speed.y = speed.y * ballNormalAccelerationCoefficient;
    double dy = (1 - accelerationCoefficientY) * _speed.y.abs();
    if(accelerationCoefficientY != 1 && dy < _acceleration.y.abs() * time){
      dy = _acceleration.y.abs() * time * 10.2;
    }

    double resultY = (_speed.y.abs() - dy);
    if(resultY < 0){
      _speed.y = 0;
    } else {
      if(_speed.y > 0){
        _speed.y = resultY;
      } else {
        _speed.y = -resultY;
      }
    }

  }

  double getAngle(){
    return _angle;
  }

  /// 获取当前偏移量，主要变化逻辑在此处理
  Offset getNextFrameOffset() {
    // 计算位移，考虑加速度和速度的影响
    var offsetX = _speed.x * time ;
    var offsetY = _speed.y * time ;

    var newOffset = Offset(_position.dx + offsetX, _position.dy + offsetY);
    //碰撞边界 速度， 一会正，一会负，反弹抖动

    var tempX = newOffset.dx;
    var tempY = newOffset.dy;
    bool isEdgeLeft = false;
    bool isEdgeRight = false;
    bool isEdgeTop = false;
    bool isEdgeBottom = false;
    // 左边界
    if (tempX < 0) {
      tempX = 0;
      setOppositeSpeed(true, false);
      isEdgeLeft = true;
    }
    // 右边界
    if (tempX > limitX - size.width) {
      tempX = limitX - size.width;
      setOppositeSpeed(true, false);
      isEdgeRight = true;
    }
    // 上边界
    if (tempY < 0) {
      tempY = 0;
      setOppositeSpeed(false, true);
      isEdgeTop = true;
    }
    // 下边界
    if (tempY > limitY - size.height) {
      tempY = limitY - size.height;
      setOppositeSpeed(false, true);
      isEdgeBottom = true;
    }

    _position = Offset(tempX, tempY);

    if(isEdgeLeft || isEdgeRight || isEdgeTop || isEdgeBottom){
      if((_speed.x.abs()  > 5) && (_speed.y.abs() > 5)){
        bool clockwise = isClockwise(_speed.x, _speed.y);
        double dAngle = 0.03;

        if(clockwise){
          if(_angleSpeed < 0){
            _angleSpeed = _angleSpeed / 2;
          } else if(_angleSpeed == 0){
            _angleSpeed = dAngle;
          }
        } else {
          if(_angleSpeed > 0){
            _angleSpeed = _angleSpeed / 2;
          } else if(_angleSpeed == 0){
            _angleSpeed = -dAngle;
          }
        }
      } else {
        _angleSpeed = _angleSpeed / 2;
      }

    }

    if(_angleSpeed.abs() < 0.0005){
      _angleSpeed = 0;
    }
    //更新角度
    _angle = _angle + _angleSpeed;

    double vX = _acceleration.x * time;
    double vY = _acceleration.y * time;
    if((isEdgeLeft && _acceleration.x < 0) || (isEdgeRight && _acceleration.x > 0)){
      vX = 0;
    }
    if((isEdgeTop && _acceleration.y < 0) || (isEdgeBottom && _acceleration.y > 0)){
      vY = 0;
    }
    //更新速度
    _speed = Speed(
      _speed.x + vX,
      _speed.y + vY,
    );
    return _position;
  }

  bool isClockwise(double speedX, double speedY){
    bool result = true;
    if(speedX > 0){
      if(speedY > 0){
        result = true;
      } else {
        result = false;
      }
    }  else {
      if(speedY > 0){
        result = false;
      } else {
        result = true;
      }
    }
    return result;
  }

  /// 碰撞到墙壁时反转速度并衰减
  void setOppositeSpeed(bool x, bool y) {
    if (x) {
      double dx = (1 - wallAttenuationCoefficient) * _speed.x.abs();
      if(dx < _acceleration.x.abs() * time){
        double resultX = (_speed.x.abs() - _acceleration.x.abs() * time * 1.2);
        if(resultX < 0){
          _speed.x = 0;
        } else {
          if(_speed.x > 0){
            _speed.x = -resultX;
          } else {
            _speed.x = resultX;
          }
        }
      } else {
        _speed.x = -_speed.x * wallAttenuationCoefficient;
      }
    }
    if (y) {
      //衰减 的量 要大于加速度的增速， 因为下一帧会先 增速 再 碰撞减速
      double dy = (1 - wallAttenuationCoefficient) * _speed.y.abs();
      if(dy < _acceleration.y.abs() * time){
        double resultY = (_speed.y.abs() - _acceleration.y.abs() * time * 1.2);
        if(resultY < 0){
          _speed.y = 0;
        } else {
          if(_speed.y > 0){
            _speed.y = -resultY;
          } else {
            _speed.y = resultY;
          }
        }
      } else {
        _speed.y = -_speed.y * wallAttenuationCoefficient;
      }
    }
  }
}

/// 速度类，表示二维平面上的速度
class Speed {
  double x;
  double y;

  Speed(this.x, this.y);
}

/// 加速度类，表示二维平面上的加速度
class Acceleration {
  double x;
  double y;

  Acceleration(this.x, this.y);
}
